<?php
/**
 * Created by PhpStorm.
 * User: chenbin
 * Date: 15-5-13
 * Time: 下午5:07
 * gamil:bingoPureLife@gamil.com
 */

namespace Promoter\Common;
use Think\Model;
use Think\Page;
/*
 *
 *配置解析类 工具类
 *
 * */
class Db{

    private $dbUtilConfig; //配置属性
    private $dict;//字典属性
    //含参构造方法
    public function Db($dbUtilConfig,$dict){
        $this->dbUtilConfig = $dbUtilConfig;
        $this->dict = $dict;
    }
    //全局数据查询展示view 构造  考虑往常情况都为<table>
    /*
     *两种方式  一种直接默认table 另外一种 反馈好 th内容和 td 的key 内容 解决特殊情况的匹配
     *type 0 table形式  1特殊模式
     * */
    public function select_view($type = 0,$method=0,$tablename){
			
         $config = json_decode(self::$dbUtilConfig,true);
         $dict = json_decode(self::$dict,true);
        //获取 show  和 key
         $data = $this->db_search($method,$tablename);
         $configDetail = $config[$tablename]['showFiled'];
         if(!$type){
            //table 模式
            $table = '<table><thead>';
             $temp = null;//保存那些有字典的属性
            foreach($configDetail as $row){
                $table .= '<th>'.$row['show'].'</th>';
                if($row['dict']){
                    $temp[$row['field']] = $row;
                }
            }
            $table .= '</thead><tbody>';
             if($data['list']){
                 foreach($data['list'] as $row){
                     $table .='<tr>';
                     foreach($configDetail as $ro){
                         //判断有没有使用字典
                         $key = $ro['field'];
                         if($ro['dict']){
                             $config = $dict[$ro['dict']];
                             if($ro['dtype'] == 'sarray'){
                                 //静态数组
                                 $table .= '<td>'.$config[$row[$key]].'';

                             }else if($ro['dtype'] == 'util_'){
                                 //操作
                                 $table .= "<td>";
                                 foreach($config as $r){
                                     //<a class="editBtns" href="tuikeguanli-add.html">编辑</a>
                                     $table .= '<a class="'.$r['class'].'" href="'.$r['url'].$row[$key].'.html">'.$r['show'].'</a>';
                                 }
                                 $table .= "</td>";
                             }else if($ro['dtype'] == 'check'){
                                 //<input type="checkbox">
                                 $table .= '<td><input type="checkbox" name="'.$key.'" value = "'.$row[$key].'"></td>';
                             }
                         }else{
                             $table .= '<td>'.$row[$key].'</td>';
                         }
                     }
                     $table .='</tr>';
                 }
             }else{
                 $table .= '<tr><td colspan="'.count($configDetail).'"><h3>当前还没有数据<h3></td></tr>';
             }

             $table .= '</tbody></table>';
             $data['list'] = $table;
             return $data;
         }else{
            //直接返回数组

            return $data;
         }

    }
    //全局数据add_edit_view view 方法
    /*
     *type 区分是增加还是edit 0 = 增加 1 = edit
     * */
    public function add_edit_view($tablename,$type){

        if($tablename){
            $config_arr = json_decode(self::$dbUtilConfig,true);

            $dict = json_decode(self::$dict,true);
            //获取需要增加的字段
            $fieldConfig = $config_arr[$tablename]['addEditFiled'];
            $title = null;
            $js = null;
            $css = null;
            $data = null;//如果是修改 需要查出此条数据信息
            $httpData = null;//当执行修改的时候 会get 带过来id
            if($type){
            //修改view 准备
                $title = "--修改";
                $httpData = I('get.');
                //$data = M($tablename)->where('`id`='."'".I('get.id')."'")->find();//找出修改的单条数据
                $data_tem = $this->db_search(0,$tablename);
                $data = $data_tem['list'][0];
            }else{
                $title = "--增加";
            }
            //考虑到前端结构多变性，封装好一个个字段对应好标签 class require default 等等 暂时对input checkbox radio  file text textarea 进行支持
            foreach($fieldConfig as $row){

                    $temp = empty($row['isrequrid']) ? "required ='".$row['isrequrid']."'" : null;
                    $default = empty($row['default']) ? "".$row['default']."" : null;
                    $class = null;
                    if($row['class']){
                        $class = 'class = "'.$row['class'].'"';
                    }
                    //处理data 和 标签
                    $html = null;
                    $value = null;
                    $value = $default;
                    if($type){
                        $value = $data[$row['filed']];
                    }
                    switch($row['type']){
                        case "text":
                            $value = 'value = "'.$value.'"';
                            $html = '<input type = "text" name ="'.$row['filed'].'" id = "'.$row['filed'].'" '.$class.''.$temp.' '.$value.'/>';
                            if($row['dict'] == "addr"){
                                $res[] = $dict['addr'];
                            }
                            $res[] = array(
                                'input'=>$html,
                                'show' =>$row['show']
                            );
                            break;
                        case "checkbox":
                            //
                            $all_checkbox = null; //该字段所有的可选值
                            $fontClass = "";
                            //获取checkbox数据
                            $dictstr = $row['dict']; //checkbox 必须有字典  因为存储的值是有根据的
                            $configDict = $dict[$dictstr];
                            $wherek = $configDict['where'];//where条件 字段关系
                            $all_checkbox = $this->dictFind($dictstr,$dict);//获取全部可选值
                         /*   //查找tablename
                            $dict_tablename = $configDict['tablename'];

                            //如果有tablename 说明需要数据库取数据

                            $dict_model = M($dict_tablename);
                            $all_checkbox =$dict_model->field($configDict['field'])->select();//获得全部*/

                            if($wherek){
                                //这里是典型的关系表存储
                                $operator = $configDict['operator'];//关系符号
                                $where = $wherek.$operator."'".$httpData['id']."'";//确保每张表都有ID 并且通过ID 修改
                                $past_checkbox = M($configDict['relatable'])->field($configDict['relafield'])->where($where)->select();//获得曾经选中的
                                //foreach()跑一边结构
                                foreach($past_checkbox as $row){
                                    $past_checkbox_ids[] = $row['id'];
                                }
                                //以上得出所有的曾经选中的分类ID（以分类ID做说明 实际上不一定是分类这种情况）
                            }
                            //拼装需要的html 判断是否有value 当有值的时候 需要做默认选中  当checkbox 可能出现存串和存关系表的情况
                            if(isset($value)){
                                //默认选中 判断是否为字符串
                                $check = explode(',',$value);
                                if(count($check) > 1){
                                    //串
                                    foreach($all_checkbox as $ro){
                                        //拼装checkbox
                                        //<input type="checkbox" name="">
                                        //row['id'] 表示当前的ID
                                        if(in_array($ro['id'],$check)){
                                            $html .= '<input type = "checkbox"  checked  value = "'.$ro['id'].'" id = "'.$row['filed'].'" name = "'.$row['filed'].'[]" '.$class.''.$temp.'><cite class = "'.$fontClass.'">'.$ro['value'].'</cite>';
                                        }else{
                                            $html .= '<input type = "checkbox"  value = "'.$ro['id'].'" id = "'.$row['filed'].'" name = "'.$row['filed'].'[]" '.$class.''.$temp.'><cite class = "'.$fontClass.'">'.$ro['value'].'</cite>';
                                        }
                                    }
                                }else{

                                    //字段 select出来
                                    foreach($all_checkbox as $ro){
                                        //拼装checkbox
                                        //<input type="checkbox" name="">
                                        //row['id'] 表示当前的ID $past_checkbox_ids 表示关系表中 已有的记录

                                        if(in_array($row['id'],$past_checkbox_ids)){
                                            $html .= '<input type = "checkbox" checked  value = "'.$ro['id'].'" id = "'.$row['filed'].'" name = "'.$row['filed'].'[]" '.$class.''.$temp.'><cite class = "'.$fontClass.'">'.$ro['value'].'</cite>';
                                        }else{
                                            $html .= '<input type = "checkbox"  value = "'.$ro['id'].'" id = "'.$row['filed'].'" name = "'.$row['filed'].'[]" '.$class.''.$temp.'><cite class = "'.$fontClass.'">'.$ro['value'].'</cite>';
                                        }
                                    }

                                }

                            }else{
                                //增加的情况
                                //显示应该有的全部
                                foreach($all_checkbox as $ro){
                                    $html .= '<input type = "checkbox" id = "'.$row['filed'].'" name = "'.$row['filed'].'[]" '.$class.''.$temp.' value = "'.$ro['id'].'"><cite class = "'.$fontClass.'">'.$ro['value'].'</cite>';
                                }
                            }
                            $res[] = array(
                                'input'=>$html,
                                'show' =>$row['show']
                            );
                            break;
                        case "select":
                             //找出全部可选情况 再根据value 确定修改还是add
                            $dictstr = $row['dict'];//select 必须有字典
                            $all_checkbox = $this->dictFind($dictstr,$dict);
                            /*
                             *
                             * <select name="">
                                    <option value="" selected>
                                    <option value="">
                                </select>
                             * */
                            //如果要加class  就直接配置进字典  checkbox 同理
                            if(isset($value)){
                                $html .= '<select name="'.$row['filed'].'" id = "'.$row['filed'].'" '.$class.''.$temp.'>';
                                foreach($all_checkbox as $row){
                                    if($row['id'] == $value){
                                        $html .= '<option value="'.$row['id'].'" selected>'.$row['value'].'</option>';
                                    }else{
                                        $html .= '<option value="'.$row['id'].'">'.$row['value'].'</option>';
                                    }
                                }
                                $html .= '</select>';
                            }else{
                                $html .= '<select name="'.$row['filed'].'" id = "'.$row['filed'].'" '.$class.''.$temp.'>';
                                foreach($all_checkbox as $row){
                                    $html .= '<option value="'.$row['id'].'">'.$row['value'].'</option>';
                                }
                                $html .= '</select>';
                            }
                            $res[] = array(
                                'input'=>$html,
                                'show' =>$row['show']
                            );
                            break;
                        case "radio":
                            /*
                             * <input type="radio" name="">
                             * */
                            $dictstr = $row['dict'];//select 必须有字典
                            $all_checkbox = $this->dictFind($dictstr,$dict);
                            $configDict = $dict[$dictstr];
                            $dict_tablename = $configDict['tablename'];
                            if(isset($value)){
                                if(!$dict_tablename){
                                    foreach($all_checkbox as $key=>$ro){
                                        if($value == $key){
                                            $html .='<input type="radio" name="'.$row['filed'].'" checked '.$class.''.$temp.' value = "'.$key.'"><cite>'.$ro.'</cite>';
                                        }else{
                                            $html .='<input type="radio" name="'.$row['filed'].'" '.$class.''.$temp.' value = "'.$key.'"><cite>'.$ro.'</cite>';
                                        }
                                    }
                                }else{
                                    foreach($all_checkbox as $ro){

                                        if($value == $ro['id']){
                                            $html .='<input type="radio" name="'.$row['filed'].'" checked '.$class.''.$temp.' value = "'.$ro['id'].'"><cite>'.$ro['value'].'</cite>';
                                        }else{
                                            $html .='<input type="radio" name="'.$row['filed'].'" '.$class.''.$temp.' value = "'.$ro['id'].'"><cite>'.$ro['value'].'</cite>';
                                        }
                                    }
                                }
                            }else{

                                if(!$dict_tablename){
                                    foreach($all_checkbox as $key=>$val){

                                        $html .='<input type="radio" name="'.$row['filed'].'" '.$class.''.$temp.' value = "'.$key.'"><cite>'.$val.'</cite>';
                                    }
                                }else{
                                    foreach($all_checkbox as $ro){

                                        $html .='<input type="radio" name="'.$row['filed'].'" '.$class.''.$temp.' value = "'.$ro['id'].'"><cite>'.$ro['value'].'</cite>';
                                    }
                                }

                            }
                            $res[] = array(
                                'input'=>$html,
                                'show' =>$row['show']
                            );

                            break;
                        case "file":
                            /*
                             *<input type = "file" >
                             * */
                            $html = '<input type="file" name = "'.$row['filed'].'" id = "'.$row['filed'].'" '.$class.''.$temp.'>';
                            $res[] = array(
                                'input'=>$html,
                                'show' =>$row['show']
                            );
                            break;
                        case "textarea":
                            /*
                             * <textarea class="text" type="text" required="" name="activeDatil" ></textarea>
                             * */
                            if(isset($value)){
                                $html = '<textarea  name="'.$row['filed'].'" id = "'.$row['filed'].'" '.$class.''.$temp.'>'.$value.'</textarea>';
                            }else{
                                $html = '<textarea  name="'.$row['filed'].'" id = "'.$row['filed'].'" '.$class.''.$temp.'></textarea>';
                            }
                            $res[] = array(
                                'input'=>$html,
                                'show' =>$row['show']
                            );
                            break;
                        case "password":
                            $html = '<input type = "password" name = "'.$row['filed'].'" id = "'.$row['filed'].'" '.$class.'>';
                            $res[] = array(
                                'input'=>$html,
                                'show' =>$row['show']
                            );
                            break;
                        case "giveup":
                            break;
                        default:
                            die("出现了意外情况，程序终止。");
                            break;
                    }

            }
            $static = $this->makeStatic($tablename,$config_arr);
            $title = $config_arr[$tablename]['title'].$title;
            $resArray = array(
                'static'=>$static,'title'=>$title,'field'=>$res,'data'=>$data_tem['list'][0]
            );
            return $resArray;
        }else{

            return null;
        }
    }
    /*
     *此方法负责 select raido checkbox 的字典查询
     * */
    public function dictFind($dictstr,$dict){

        $configDict = $dict[$dictstr];
        //查找tablename
        $dict_tablename = $configDict['tablename'];
        //如果有tablename 说明需要数据库取数据
        if($dict_tablename){
            $wherek = $configDict['where'];//where条件 字段关系
            $dict_model = M($dict_tablename);
            $all_checkbox =$dict_model->field($configDict['field'])->select();//获得全部
        }else{
            //类似这种情况"sex":{"0":"男","1":"女","2":"未知"},
            $all_checkbox = $configDict;
        }
        return $all_checkbox;
    }

    //总配置变量 因为别的方法一开始 都会解析好这个数组，所以直接当参数传 节省
    public function makeStatic($tablename,$config_arr){
        //统一加入js  css title 于数组
        $css = $config_arr[$tablename]['css'];
        $js = $config_arr[$tablename]['js'];
        //重构
        $static = null;
        if($css){
            foreach($css as $row){
                $static .= '<link href="'.$row.'" type="text/css" rel="stylesheet">';
            }
        }
        if($js){
            foreach($js as $row){
                $static .= '<script src="'.$row.'" type="text/javascript"></script>';
            }
        }
        return $static;
    }
    //全局搜索方法
    /*
     * method :表单提交方法 0 为get 1为post  默认get
     *
     * tablename : 表名
     *
     * */
    public  function db_search($method = 0,$tablename){

        $config = json_decode(self::$dbUtilConfig,true);

        //确定搜索方式 不过都准备采用get方式  凡事都有特殊 加个参数判断
        $search = $config[$tablename]['serach'];
        $formData = $method ? I('post.') : I('get.');
        $field = $search['field'] ? $search['field'] : '*';
        $table = null;
        $where = null;
        $order = $search['order'] ? $search['order'] : null;
        $group = $search['group'] ? $search['group'] : null;
        $limit = $search['limit'] ? $search['limit'] : 10;
        //查询条件列表 以及可能有的值
        $find = null;
        //组装表
        foreach($search['tables'] as $k => $v){
            $table[$v['tableName']] = $v['as'];
           // $table .= $v['tableName']." as ".$v['as'].",";
        }
        //$table = substr($table,0,-1);
        //组装where
        //如果多表 检查关系字段
        if(count($search['tables'])>1){
            if($search['rela']){
                $where .= $search['rela']."";
            }
        }
        $boo = true;//临时加的   要改
        foreach($search['where'] as $key=>$row){

            /*
             * 扩展下 比如说get 中key = all 则所有配置项 按照或者关系走
             * TODO 待完善
             * */
            $temp = $formData[$row['get']];//从前台拿来数据
            if($key>=1){
                $value = isset($temp)?$temp:$row['show'];
                $find[] = array('value'=>$value,'name'=>$row['get']);
            }

            //拼装
            if($temp){

                if($where != "" && $formData[$search['where'][0]['get']] && $boo){
                    $where .= " AND";
                    $boo = false;
                }
                $wheretype = $row['operator'];
                //加入连接符
                $where .= " ".$row['linkedOperator']." ";
                //PHP switch case 进入case 不进入default
                if($wheretype == "not like" || $wheretype == "like"){
                    $match = $row['likeMatch'];
                    if($wheretype == "like"){
                        $where .= $row['forWhere'].' like ';
                    }else{
                        $where .= $row['forWhere'].' not like ';
                    }
                    //判断是左 还是右 还是全
                    if($match == 'right'){
                        //右匹配
                        $where .= "'$temp%'";
                    }else if($match == 'left'){
                        $where .= "'%$temp'";
                        //左匹配
                    }else{
                        $where .= "'%$temp%'";
                        //全匹配
                    }

                }else{
                    //非like 情况
                    $where .= $row['forWhere']." ".$row['operator']." ".''.$temp.'';
                }

            }
        }

        //按照tp框架层封装系列方法 实现带分页查询
        $modelsel = D();
        $modelcou = D();
        $count = $modelcou->Table($table)->where($where);

        //无奈 又要根据group  order 进行判断 由于多表 无法默认order by  和group by  除非配置默认  但是并不是所有都需要group by
        $list  = $modelsel->Table($table)
            ->where($where)
            ->field($field);
        if($order && $group){
            $list = $list->group($group)
                ->order($order);
            $count = $count->group($group);
        }else if($group){
            $list = $list->group($group);
            $count = $count->group($group);
        }else if($order){
            $list = $list->order($order);
        }

        $count = $count->count();

        $Page  = new Page($count,$limit);
        $show  = $Page->show();

        $list = $list->limit($Page->firstRow.','.$Page->listRows)
            ->select();
        $title = $config[$tablename]['title']."查询";
        $static = $this->makeStatic($tablename,$config);

        return array('show'=>$show,'list'=>$list,'title'=>$title,'static'=>$static,'find'=>$find);
    }

    //过滤无用字段  parm : way  过滤那一部分字段  默认增加和修改
    /*
     *config root name
     * */
    private function filterElse($data,$tootname,$way="addEditFiled"){
        $config_arr = json_decode(self::$dbUtilConfig,true);
        $retVal = null;
        $config =$config_arr[$tootname][$way];//获取字段
        foreach($config as $row){
            if(isset($data[$row['filed']])){
                //构造干净的
                if($row['type'] == 'checkbox'){
                    $retVal[$row['filed']] = implode(',',$data[$row['filed']]);
                }else{
                    $retVal[$row['filed']] = $data[$row['filed']];
                }
            }
        }
        return $retVal;
    }
//全局数据库增加方法
    /*
     * 如果直接在$_GET[] $_POST[] 加 是不行的 因为做了字段过滤 必须采用模式2
     * parm : type? 1为自动模式 2为半自动模式  0为非自动模式  默认自动模式
     * parm : method  表单提交方法 0 为get 1为post  默认post
     * tablename : 表名称
     * extra : 选择手动方法或者 半自动方法时候 追加的数据  这一部分数据 没有做过滤
     * fitter ：
     * */
    //数据全局add方法
    public function db_add($type = 1,$method = 1,$tableName,$extra,$rootConfig){
            $result = null;
            $model = M($tableName);
            $formData = $method ? I('post.') : I('get.');

            switch($type){
                 case 0:
                     //手动模式
                     $result = $model->add($extra);
                    break;
                case 1:
                    //自动模式
                    if($rootConfig) $data = $this->filterElse($formData,$rootConfig);
                    $result = $model->add($data);
                    break;
                case 2:
                    if($rootConfig) $data = $this->filterElse($formData,$rootConfig);
                    $data = array_merge($data,$extra);
                    $result = $model->add($data);
                    //混合模式
                    break;
            }
        return $result;
    }

    //全局数据库修改方法
    /*
     *  parm : type? 1为自动模式 2为半自动模式  0为非自动模式  默认自动模式
     * parm : method  表单提交方法 0 为get 1为post  默认post
     * tablename : 表名称
     * extra : 选择手动方法或者 半自动方法时候 追加的数据  这一部分数据 没有做过滤
     * */
    public function db_edit($type = 1,$method = 1,$tableName,$extra,$where,$rootConfig){
            $result = null;
            $model = M($tableName);
            $formData = $method ? I('post.') : I('get.');
            if(!$where){
                $where = array('id'=>$formData['id']);
            }

            switch($type){
                case 0:
                    //手动模式
                    $result = $model->where($where)->save($extra);
                    break;
                case 1:
                    //自动模式
                    if($rootConfig) $formData = $this->filterElse($formData,$rootConfig);

                    $result = $model->where($where)->save($formData);
                    break;
                case 2:
                    if($rootConfig) $formData = $this->filterElse($formData,$rootConfig);
                    $formData = array_merge($formData,$extra);
                    $result = $model->where($where)->save($formData);
                    //混合模式
                    break;
                default:
                    die("处理出错");
            }
        return $result;
    }
    /*
     * 删除
     *id  默认get.id
     * 有where的情况忽略id
     * */
    public function db_singel_del($tablename,$where){
        $m = M($tablename );
        if($where){
            $res = $m->where($where)->delete();
            return $res;
        }else{
            if(I('get.id')){
               $res = $m->where(array('id'=>I('get.id')))->delete();
                return $res;
            }else{
                return false;
            }
        }
    }
    /*
     * 多表删除操作 事务处理
     * array(
     *      array('tablename'=>"tablename",'where'=>"where")
     * )
     * */
    public function db_lotDel($array){
        if($array){
            $model = M();
            $model->startTrans();//开启事务
            $boo = true;
            foreach($array as $row){
                $boo = $model->table(C('DB_PREFIX').$row['tablename'])->where($row['where'])->delete();
                if(!$boo){
                    $model->rollback();
                    return false;
                }
            }
            $model->commit();
            return true;
        }else{
           return false;
        }
    }
    /*
     *多表增加 事务处理 修改 增加
     *
     * array 格式
     * array(
     *      array('tablename'=>"tablename",'where'=>"where",'data'=>$data)
     * )
     * $type  传递函数增加或者删除
     * */

    public function db_lot_add_edit($type,$array){
        $type_arr = array(
            'add','save'
        );
        if(!in_array($type,$type_arr)) return false;
        if(!$array) return false;
        $model = M();
        $model->startTrans();//开启事务
        $boo = true;
        foreach($array as $row){
            $boo = $model->table(C('DB_PREFIX').$row['tablename'])->where($row['where'])->$type($row['data']);
            if(!$boo){
                $model->rollback();
                return false;
            }
        }
        $model->commit();
        return true;
    }
    //增强版事务处理 支持简单的增删改  
    public function db_lot_add_edit_ext($array){
        $type_arr = array(
            'add','save','delete'
        );
        if(!$array) return false;
        $model = M();
        $model->startTrans();//开启事务
        $boo = true;
        foreach($array as $row){
            if(!in_array($row['type'],$type_arr)) return false;
            $boo = $model->table(C('DB_PREFIX').$row['tablename'])->where($row['where'])->$row['type']($row['data']);
            if(!$boo){
                $model->rollback();
                return false;
            }
        }
        $model->commit();
        return true;
    }
}